#pragma once
#include <iostream>
#include <memory>
#include <poll.h>
// #include <sys/select.h>
#include "Socket.hpp"
#include "Log.hpp"

using namespace socket_ns;
using namespace log_ns;

class PollServer {
private:
    static const int gnum = sizeof(fd_set) * 8;
    static const int gdefaultfd = -1;
    static const int gsize = 4096;

    void HandlerListenEvents()
    {
        InetAdrr Addr;
        int sockfd = _listensock->CreateAccepte(&Addr);
        if (sockfd > 0) {
            LOG(INFO, "listen socket recive a sockfd, client info: %s\n", Addr.AddrString().c_str());
            // 还不一定能将刚收到的sockfd加入到fd array中，因为array中的元素可能已经装满
            bool flag = false;
            // 将获取到的套接字放入到fd array中
            for (int j = 0; j < gnum; j++) {
                if (_fds[j].fd != gdefaultfd)
                    continue;
                _fds[j].fd = sockfd;
                _fds[j].events = POLLIN;
                _fds[j].revents = 0;
                flag = true;
                break;
            }
            if (!flag) {
                LOG(WARNING, "fd array is full\n");
                close(sockfd);
            }
        }

    }

    void HandlerOtherEvents(int i) {
        LOG(INFO, "other sockfd do\n");
        // 进行读操作，然后将其打印出来
        char buff[gsize];
        int n = read(_fds[i].fd, buff, sizeof(buff) - 1);
        if (n > 0) {
            buff[n] = 0;
            std::cout << "echo > " << buff << std::endl;
            // 返回一个http报文
            std::string content = "<html><body><h1>hello Linux!</h1></body></html>";
            std::string echo_str = "HTTP/1.0 200 OK\r\n";
            echo_str += "Content-Type: text/html\r\n";
            echo_str += "Content-Length: " + std::to_string(content.size()) + "\r\n\r\n";
            echo_str += content;
            // echo_str += buffer;
            send(_fds[i].fd, echo_str.c_str(), echo_str.size(), 0); // 临时方案            
        } else if (n == 0) {
            // 读操作结束，处理结束，将套接字抹除
            LOG(INFO, "client quit...\n");
            close(_fds[i].fd);
            _fds[i].fd = gdefaultfd;      
            _fds[i].events = 0;  
            _fds[i].revents = 0;  
        } else {
            LOG(ERROR, "read error\n");
            close(_fds[i].fd);
            _fds[i].fd = gdefaultfd;     
            _fds[i].events = 0;  
            _fds[i].revents = 0;  
        }
    }

    void HandlerEvents() {
        // 检查是哪些fd
        for (int i = 0; i < gnum; i++) {
            // 判断当前的fd是否有效
            if (_fds[i].fd == gdefaultfd || _fds[i].revents != POLLIN)
                continue;
            // 当走到这里的时候_fd_array[i]已经准备好了，会直接运行下去，不会阻塞
            if (_fds[i].fd == _listensock->GetSockfd()) {
                // listensocket接收到一个连接请求
                HandlerListenEvents();
            } else {
                // 其他socket收到了信息
                HandlerOtherEvents(i);
            }
        }
    }    

    void PrintDebug() {
        std::cout << "the socketfd have: ";
        for (int i = 0; i < gnum; i++) {
            if (_fds[i].fd == gdefaultfd)
                continue;
            std::cout << _fds[i].fd << " ";
        }
        std::cout << std::endl;
    }

public:
    PollServer(uint16_t port) : _listensock(std::make_unique<TcpSocket>(port)) {
        _listensock->BuildListenSocket(port);
        // 初始化数组中的每个值
        for (int i = 0; i < gnum; i++) {
            struct pollfd poev;
            poev.fd = gdefaultfd;
            poev.events = 0;
            poev.revents = 0;
            _fds[i] = poev;
        }
    }

    void Init() {
        // 将listensockfd放入到数组中
        struct pollfd pofd;
        pofd.fd = _listensock->GetSockfd();
        pofd.events = POLLIN;
        pofd.revents = 0;
        _fds[0] = pofd;
    }

    void Start() {
        while (true) {

            int timeout = 1000;
            // 当 poll 检测到数组中的文件描述符小于0的时候会选择自动忽略
            int n = poll(_fds, gnum, timeout);

            // sleep(1);
            if (n > 0) {
                // 现在已经发现存在文件描述符准备好
                // 可以让去直接处理对应的文件描述符了
                LOG(INFO, "begin to deal with the things\n");
                PrintDebug();
                HandlerEvents();
            } else if (n == 0) {
                LOG(INFO, "over time, to wait next rotation\n");
                continue;
            } else {
                LOG(ERROR, "select error\n");
                break;
            }
        }
    }

    ~PollServer() {}
private:
    // fd_set _rfds;

    std::unique_ptr<Socket> _listensock;
    struct pollfd _fds[gnum];
};